package org.smth.search.persistence.impl;

import com.google.inject.Inject;
import com.google.inject.Singleton;
import com.mysql.jdbc.MysqlDataTruncation;
import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.smth.search.persistence.DataService;
import org.smth.search.pojos.OnePost;
import org.smth.search.types.Post;
import org.smth.search.types.PostItem;

import javax.persistence.EntityManager;
import java.util.List;
import java.util.ArrayList;
import java.util.Properties;
import java.util.Arrays;

@Singleton
public class DataServiceImpl implements DataService {

	@Inject
	private JpaDao dao;

	private Class[] catchs = new Class[] { MysqlDataTruncation.class }; //需要忽略的数据库异常

	private Log log = LogFactory.getLog(this.getClass());

	public void savePost(PostItem item, Post post) {
		final OnePost one = new OnePost();
		try {
			BeanUtils.copyProperties(one, item);
			BeanUtils.copyProperties(one, post);
		} catch (Exception e) {
			RuntimeException ex;
			if (e instanceof RuntimeException) {
				ex = (RuntimeException) e;
			} else {
				ex = new RuntimeException(e);
			}
			throw ex;
		}
		try {
			dao.persist(one);
		} catch (Throwable t) {
			if (catchs != null && catchs.length > 0) {
				Throwable ex = t;
				while (ex != null) {
					for (Class ext : catchs) {
						if (ext != null && ext.isInstance(ex)) {
							log.warn("出现一个被捕获的数据库异常");
							log.warn(t);
							return;
						}
					}
					ex = ex.getCause();
				}
			}
			RuntimeException ex;
			if (t instanceof RuntimeException) {
				ex = (RuntimeException) t;
			} else {
				ex = new RuntimeException(t);
			}
			throw ex;
		}
	}

	public int getLastId(final String board) {
		return dao.readonlyCall(new JpaCallback<Integer>() {
			public Integer call(EntityManager manager) {
				String sql = "select max(c.id) from OnePost c where c.boardName=?";
				List list = manager.createQuery(sql).setParameter(1, board.toLowerCase()).getResultList();
				if (list == null || list.size() != 1) {
					return 0;
				} else {
					Integer one = (Integer) list.get(0);
					if (one == null) {
						one = 0;
					}
					return one;
				}
			}
		});
	}

	private static String SelSqlA = "select c from OnePost c where c.postId>? order by c.postId";

	public List<OnePost> getPostsWithIdGT(final int id, final int max) {
		return dao.readonlyCall(new JpaCallback<List<OnePost>>() {
			@SuppressWarnings("unchecked")
			public List<OnePost> call(EntityManager manager) {
				return manager.createQuery(SelSqlA).setParameter(1, id).setMaxResults(max).getResultList();
			}
		});
	}

	protected StringBuffer appendIdWheres(StringBuffer buffer, int... ids) {
		if (buffer == null) {
			buffer = new StringBuffer();
		}
		int len = ids.length;
		buffer.append('(');
		for (int i = 0; i < len; i++) {
			if (i > 0) {
				buffer.append(" or ");
			}
			buffer.append("c.postId=").append(ids[i]);
		}
		buffer.append(')');
		return buffer;
	}

	public List<OnePost> getPostsByIds(final int... ids) {
		return dao.readonlyCall(new JpaCallback<List<OnePost>>() {
			@SuppressWarnings("unchecked")
			public List<OnePost> call(EntityManager manager) {
				if (ids == null || ids.length < 1) {
					return new ArrayList<OnePost>(0);
				}
				StringBuffer buffer = new StringBuffer("select c from OnePost c where ");
				appendIdWheres(buffer, ids);
				return manager.createQuery(buffer.toString()).getResultList();
			}
		});
	}

	public List getPostsStatistic() {
		return dao.readonlyCall(new JpaCallback<List>() {
			@SuppressWarnings("unchecked")
			public List call(EntityManager manager) {
				List list1 = manager.createQuery("select boardName,count(*),max(postId) from OnePost group by boardName order by boardName").getResultList();
				int size = list1.size();
				if (size > 0) {
					int[] ids = new int[size];
					for (int i = 0; i < size; i++) {
						ids[i] = ((Number) ((Object[]) list1.get(i))[2]).intValue();
					}
					StringBuffer buffer = new StringBuffer("select boardName,postTime from OnePost c where ");
					appendIdWheres(buffer, ids);
					List list2 = manager.createQuery(buffer.toString()).getResultList();
					Properties prop = new Properties();
					for (Object o : list2) {
						Object[] os = (Object[]) o;
						prop.setProperty((String) os[0], (String) os[1]);
					}
					for (int i = 0; i < size; i++) {
						Object[] os = (Object[]) list1.get(i);
						os = Arrays.copyOf(os, 3);
						os[2] = prop.get(os[0]);
						list1.set(i, os);
					}
				}
				return list1;
			}
		});
	}

}
